import React, {
  createContext,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState
} from 'react'
import type { ReactNode } from 'react'
import { StorageFactory } from '../../../services/storage'
import type { StorageError } from '../../../services/storage/types'
import type { Content } from '../../../types/document'
import {
  createInitialState,
  defaultTheme,
  deriveStats,
  ensureTextDocument,
  mergeDraftIntoContent
} from './helpers'
import {
  type DocumentStateActions,
  type DocumentStateContextValue,
  type DocumentTheme,
  type DocumentViewState
} from './types'
import { createEmptyContent } from '../../../utils/documentUtils'
import { ContentType } from '../../../types/document'

const INITIAL_STATE = createInitialState()

export interface DocumentStateProviderProps {
  initialDocumentId?: string
  children: ReactNode
}

export const DocumentStateContext = createContext<DocumentStateContextValue | undefined>(
  undefined
)

const DocumentStateProvider: React.FC<DocumentStateProviderProps> = ({
  initialDocumentId,
  children
}) => {
  const [currentDocument, setCurrentDocument] = useState<DocumentViewState['currentDocument']>(
    INITIAL_STATE.currentDocument
  )
  const [draftContent, setDraftContent] = useState(INITIAL_STATE.draftContent)
  const [isDirty, setIsDirty] = useState(INITIAL_STATE.isDirty)
  const [isLoading, setIsLoading] = useState(INITIAL_STATE.isLoading)
  const [lastSavedAt, setLastSavedAt] = useState<Date | null>(INITIAL_STATE.lastSavedAt)
  const [error, setError] = useState<StorageError | null>(INITIAL_STATE.error)
  const [theme, setThemeState] = useState<DocumentTheme>(defaultTheme)
  const [stats, setStats] = useState(INITIAL_STATE.stats)

  const initializedRef = useRef(false)

  // 使用 ref 保持最新状态值,避免 useCallback 依赖频繁变化
  const currentDocumentRef = useRef(currentDocument)
  const draftContentRef = useRef(draftContent)

  useEffect(() => {
    currentDocumentRef.current = currentDocument
  }, [currentDocument])

  useEffect(() => {
    draftContentRef.current = draftContent
  }, [draftContent])

  const applyDocument = useCallback(
    (content: Content, options: { markSaved?: boolean } = {}) => {
      const safeContent = ensureTextDocument(content)
      const nextDraft = safeContent.type === ContentType.TEXT_DOCUMENT ? safeContent.data.content : ''

      setCurrentDocument(safeContent)
      setDraftContent(nextDraft)
      setStats(deriveStats(nextDraft))
      setIsDirty(false)
      setLastSavedAt(options.markSaved ? safeContent.updatedAt : null)
    },
    []
  )

  const handleLoadFailure = useCallback(
    (id: string | undefined, storageError: StorageError) => {
      console.error('[DocumentState] 文档加载失败', { id, error: storageError })
      setError(storageError)
    },
    []
  )

  const loadDocument = useCallback<NonNullable<DocumentStateActions['loadDocument']>>( async (id: string) => {
    setIsLoading(true)
    setError(null)

    try {
      const storage = StorageFactory.getAdapter()
      const result = await storage.getContentById(id)
      if (!result.ok) {
        handleLoadFailure(id, result.error)
        const fallback = createEmptyContent(ContentType.TEXT_DOCUMENT, '')
        applyDocument(fallback)
        throw result.error
      }

      if (result.data) {
        applyDocument(result.data, { markSaved: true })
        console.info('[DocumentState] 已加载文档', { id: result.data.id })
      } else {
        const empty = createEmptyContent(ContentType.TEXT_DOCUMENT, '')
        applyDocument(empty)
        console.info('[DocumentState] 未找到文档，已创建空白文档', { id })
      }
    } finally {
      setIsLoading(false)
    }
  }, [applyDocument, handleLoadFailure])

  const createNewDocument = useCallback<NonNullable<DocumentStateActions['createNewDocument']>>( async (title?: string) => {
    const empty = createEmptyContent(ContentType.TEXT_DOCUMENT, title || '')
    applyDocument(empty)
    setError(null)
    console.info('[DocumentState] 新建文档', { id: empty.id })
  }, [applyDocument])

  const updateDraft = useCallback<NonNullable<DocumentStateActions['updateDraft']>>(content => {
    setDraftContent(content)
    setStats(deriveStats(content))
  }, [])

  const updateTitle = useCallback<NonNullable<DocumentStateActions['updateTitle']>>(title => {
    if (!currentDocumentRef.current) {
      return
    }
    setCurrentDocument(prev => {
      if (!prev) return prev
      return { ...prev, title }
    })
    setIsDirty(true)
  }, [])

  const saveDocument = useCallback<NonNullable<DocumentStateActions['saveDocument']>>( async () => {
    setIsLoading(true)
    setError(null)

    try {
      // 使用 ref 获取最新值
      const baseContent = ensureTextDocument(currentDocumentRef.current)

      // 如果标题为空,自动生成一个标题
      const contentWithTitle = baseContent.title.trim() === ''
        ? { ...baseContent, title: `文档 ${new Date().toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }).replace(/\//g, '-')}` }
        : baseContent

      const merged = mergeDraftIntoContent(contentWithTitle, draftContentRef.current)

      const storage = StorageFactory.getAdapter()
      const result = await storage.saveContent(merged)

      if (!result.ok) {
        setError(result.error)
        console.error('[DocumentState] 保存失败', result.error)
        throw result.error
      }

      setCurrentDocument(merged)
      setIsDirty(false)
      setLastSavedAt(merged.updatedAt)
      setStats(deriveStats(draftContentRef.current))

      const recentResult = await storage.listRecent()
      if (!recentResult.ok) {
        console.warn('[DocumentState] 更新最近文档列表失败', recentResult.error)
      }

      console.info('[DocumentState] 已保存文档', { id: merged.id })
    } finally {
      setIsLoading(false)
    }
  }, [])

  const setTheme = useCallback<NonNullable<DocumentStateActions['setTheme']>>(themeValue => {
    setThemeState(themeValue)
  }, [])

  const resetError = useCallback<NonNullable<DocumentStateActions['resetError']>>(() => {
    setError(null)
  }, [])

  useEffect(() => {
    if (!currentDocument) {
      setIsDirty(draftContent.trim().length > 0)
      return
    }

    if (currentDocument.type !== ContentType.TEXT_DOCUMENT) {
      setIsDirty(false)
      return
    }

    setIsDirty(draftContent !== currentDocument.data.content)
  }, [currentDocument, draftContent])

  useEffect(() => {
    if (initializedRef.current) {
      return
    }

    initializedRef.current = true

    if (initialDocumentId) {
      loadDocument(initialDocumentId).catch(error => {
        console.warn('[DocumentState] 初始加载失败，fallback空白文档', error)
        const fallback = createEmptyContent(ContentType.TEXT_DOCUMENT, '')
        applyDocument(fallback)
      })
      return
    }

    createNewDocument('').catch(error => {
      console.error('[DocumentState] 初始化空白文档失败', error)
    })
  }, [applyDocument, createNewDocument, initialDocumentId, loadDocument])

  const state = useMemo<DocumentViewState>(() => ({
    currentDocument,
    draftContent,
    isDirty,
    isLoading,
    lastSavedAt,
    error,
    theme,
    stats
  }), [currentDocument, draftContent, error, isDirty, isLoading, lastSavedAt, stats, theme])

  const actions = useMemo<DocumentStateActions>(() => ({
    loadDocument,
    createNewDocument,
    updateDraft,
    updateTitle,
    saveDocument,
    setTheme,
    resetError
  }), [createNewDocument, loadDocument, resetError, saveDocument, setTheme, updateDraft, updateTitle])

  const contextValue = useMemo<DocumentStateContextValue>(() => ({
    state,
    actions
  }), [actions, state])

  return (
    <DocumentStateContext.Provider value={contextValue}>
      {children}
    </DocumentStateContext.Provider>
  )
}

export default DocumentStateProvider
